<?php
	
	namespace Aspic\Security;
	
	use Aspic as A;
	
	use Aspic\Security\Security as S;

	class Captcha {

		use A\Preset\OptionTrait {
			__construct as optionTraitInit;
		}
		
		protected $placeToStore;
		protected $requestStore;
		
		protected $_width;
		protected $_height;
		
		protected $_textLength;
		protected $_fontsPaths;
		protected $_textSize;
		protected $_lettersSpace;
		
		protected $_startX;
		
		protected $_rotateStartRange;
		protected $_rotateEndRange;
		
		protected $_linesNumber;
		
		protected $_backgroundColor;
		protected $_textColors;
		protected $_linesColors;
		
		/**
		* @param mixed $placeToStore Place to store correct captcha string
		* @param mixed $requestStore Place to get user decoded captcha string (like $_POST['captcha'])
		*/
		public function __construct(&$placeToStore = null, array $fontsPaths = array()) {
			$this->optionTraitInit();
			
			$this->setPlaceToStore($placeToStore);
			$this->setRequestStore($_POST['captcha']);
			
			$this->opt('width', 70);
			$this->opt('height', 30);
			
			$this->opt('textLength', 5);
			$this->opt('fontsPaths', $fontsPaths);
			$this->opt('textSize', 12);
			$this->opt('lettersSpace', 13);
			
			$this->opt('rotateStartRange', -18);
			$this->opt('rotateEndRange', 18);
			
			$this->opt('startX', 10);
			$this->opt('linesNumber', 3);
			
			$this->opt('backgroundColor', 'FFFFFF'); // White
			
			$this->opt('textColors', array(
				'000000',  // Black
				'0000FF',  // Blue
				'FF0000',  // Red
				// '00FF00',  // Green
				// 'FFFF00',  // Yellow
				// 'FF00FF',  
				// '00FFFF',  
			));
			
			$this->opt('linesColors', $this->opt('textColors'));
		}
		
		public function setPlaceToStore(&$placeToStore) {
			$this->placeToStore = &$placeToStore;
			// $this->placeToStore = 77;
		}
		
		public function setRequestStore(&$requestStore) {
			$this->requestStore = &$requestStore;
		}
		
		public function showImage($text = null) {
			if($text == null) {
				$text = S::getRandomString($this->opt('textLength'), true, true);
			}
			
			$captcha = $this->generateCaptcha($text);

			header('content-type: image/png');
			
			imagepng($captcha);
			
			imagedestroy($captcha);
			$this->placeToStore = $text;
			// var_dump($this->placeToStore);
			// var_dump($text);
			$session = A\Registry::get('session');
			
			// $session->newClientCaptcha = 22;
			// var_dump($this);
			// var_dump($_POST);
			// var_dump($session);
			
			return $text;
		}
		
		protected function generateCaptcha($text) {
			$captcha = imagecreatetruecolor($this->opt('width'), $this->opt('height'));
			
			$fonts = $this->opt('fontsPaths');
			$backgroundColor = $this->getColorIndexFromHexa($captcha, $this->opt('backgroundColor'));
			$textColors = $this->opt('textColors');
			$linesColors = $this->opt('linesColors');
			
			imagefill($captcha, 0, 0, $backgroundColor);
			
			$black = imagecolorallocate($captcha, 0, 0, 0);
			
			for($i = 0; $i < $this->opt('linesNumber'); ++$i) {
				$color = $this->getColorIndexFromHexa($captcha, A\UArray::randValue($linesColors));
				
				$startBorderPoint = $this->getRandomBorderPoint();
				$borders = array(0, 1, 2, 3);
				unset($borders[$startBorderPoint[2]]);
				
				$endBorderPoint = $this->getRandomBorderPoint($borders);
				// var_dump($startBorderPoint[2], $endBorderPoint[2]);
				imageline($captcha, $startBorderPoint[0], $startBorderPoint[1], $endBorderPoint[0], $endBorderPoint[1], $color);
			}
			
			// imagestring($captcha, 5, 13, 7, $text, $black);
			// var_dump(imagettftext($captcha, 10, 10, 13, 7, $black, 'courrier', $text));
			// imagettftext($captcha, $this->opt('textSize'), 10, 10, 25, $black, $font, $text);
			$currX = $this->opt('startX');
			// var_dump(A\UArray::randValue(range($this->opt('rotateStartRange'), $this->opt('rotateEndRange'))));
			for($i = 0; $i < strlen($text); ++$i) {
				$font = $fonts[array_rand($fonts)];
				$color = $this->getColorIndexFromHexa($captcha, A\UArray::randValue($textColors));
				
				imagettftext(
					$captcha, 
					$this->opt('textSize'), 
					A\UArray::randValue(range($this->opt('rotateStartRange'), $this->opt('rotateEndRange'))), 
					$currX, 
					25, 
					$color, 
					$font, 
					$text[$i]);
				
				$currX += $this->opt('lettersSpace');
			}
			
			return $captcha;
		}
		
		/**
		* Return an array: 0=>x, 1=>y, 2=>border with point on
		* @param bool $pointOnBorderCenter If true point will only be on the center part of the border (to avoid line that not throw any char)
		*/
		protected function getRandomBorderPoint(array $possibleBordersNumbers = array(0, 1, 2, 3), $pointOnBorderCenter = true) {
			$border = A\UArray::randValue($possibleBordersNumbers); // 0 is top, 1 is right, ..
			
			$div = 4;
			$mul = $div - 1;
			
			if($pointOnBorderCenter) {
				$xStart = ($this->opt('width') / $div);
				$xEnd = ($this->opt('width') / $div) * $mul;
				
				$yStart = ($this->opt('height') / $div);
				$yEnd = ($this->opt('height') / $div) * $mul;
			}
			
			switch($border) {
				case 0:
					$x = mt_rand($xStart, $xEnd);
					$y = 0;
					break;
				
				case 1:
					$x = $this->opt('width');
					$y = mt_rand($yStart, $yEnd);
					break;
				
				case 2:
					$x = mt_rand($xStart, $xEnd);
					$y = $this->opt('height');
					break;
				
				case 3:
					$x = 0;
					$y = mt_rand($yStart, $yEnd);
					break;
					
			}
				
			return array($x, $y, $border);
		}
		
		public function isCaptchaValid($text = null, $unsetText = true) {
			if(is_null($text)) {
				$text = $this->requestStore;
			}
			
			$valid = ($text === $this->placeToStore);
			
			// var_dump($text, $this->placeToStore);
			
			if($unsetText) {
				$this->placeToStore = null;
			}
			
			return $valid;
		}
		
		/**
		* Return color index (from imagecolorallocate) from a color like "FF00FF"
		*/
		protected function getColorIndexFromHexa($img, $hexa) {
			$split = str_split($hexa, 2);
			
			$red   = hexdec($split[0]);
			$green = hexdec($split[1]);
			$blue  = hexdec($split[2]);
			
			return imagecolorallocate($img, $red, $green, $blue);
		}
		
	}
	
?>